/*
	This file is a part of Awesomium, a library that makes it easy for 
	developers to embed web-content in their applications.

	Copyright (C) 2009 Adam J. Simmons

	Project Website:
	<http://princeofcode.com/awesomium.php>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
	02110-1301 USA
*/

#include "WebView/WebViewProxy.h"
#include "API/WebCore.h"
#include "WebView/WindowlessPlugin.h"	
#include "API/WebViewEvent.h"
#include "WebView/NavigationController.h"
#include "WebCore/WebCoreProxy.h"

#include "WebSize.h"
#include "WebScreenInfo.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "WebPopupMenuInfo.h"
#include "WebDataSource.h"
#include "WebURLResponse.h"
#include "net/base/base64.h"
//mgdesign, chrome v5: replace by:
//#include "base/base64.h"
#include "skia/ext/platform_canvas.h"
#include <assert.h>

#include "webkit/glue/media/buffered_data_source.h"
#include "webkit/appcache/appcache_interfaces.h"
#include "base/process_util.h"
#include "media/base/media.h"
#include "media/base/media_format.h"
#include "media/base/factory.h"
#include "media/filters/audio_renderer_impl.h"
#include "webkit/glue/webmediaplayer_impl.h"
#include "webkit/glue/media/media_resource_loader_bridge_factory.h"

#include "webkit/glue/webplugin_impl.h"
#include "third_party/WebKit/WebKit/chromium/public/WebConsoleMessage.h"
#include "webkit/glue/glue_serialize.h"
#include "webkit/glue/media/simple_data_source.h"
#include "net/base/net_errors.h"
#include <third_party/WebKit/WebKit/chromium/public/WebBindings.h>

// Sylvain
#include <sstream>

#ifdef _WIN32
#include "win/WebInputEventFactory.h"
#else
#ifdef __APPLE__
#include "mac/WebInputEventFactory.h"
#endif
#endif

#ifndef _WIN32
// For gettimeofday.
#include <sys/time.h>
#endif

typedef WebKit::WebURLResponse WebResponse;
typedef WebKit::WebURLRequest WebRequest;
typedef WebKit::WebURLError WebError;

// Defined in WebkitGlue.cpp:
std::wstring stringToWide(const std::string &stringToConvert);

static std::wstring WebStringToWString(const WebKit::WebString &str) {
	return stringToWide(str.utf8());
}

WebViewProxy::WebViewProxy(int width, int height, bool enableAsyncRendering, int maxAsyncRenderPerSec, Awesomium::WebView* parent)
  : width(width), height(height), canvas(0),
    mouseX(0), mouseY(0), view(0), parent(parent),
    isPopupsDirty(false), 
    clientObject(0), enableAsyncRendering(enableAsyncRendering), isAsyncRenderDirty(false),
    maxAsyncRenderPerSec(maxAsyncRenderPerSec), transparencyMode(Awesomium::WebView::TM_OPAQUE),
    pageID(-1), nextPageID(1)
{
	if (maxAsyncRenderPerSec <= 1)
    maxAsyncRenderPerSec = 1;
 
  if (maxAsyncRenderPerSec > 300)
		maxAsyncRenderPerSec = 300;

	renderBuffer = new Awesomium::RenderBuffer(width, height);
  
  bool is_opaque_canvas = (transparencyMode != Awesomium::WebView::TM_CANVAS_ALPHA_CHANNEL);
	canvas = new skia::PlatformCanvas(width, height, is_opaque_canvas);

	navController = new NavigationController(this);

	if(enableAsyncRendering)
		asyncRenderBuffer = new Awesomium::RenderBuffer(width, height);
	else
		asyncRenderBuffer = 0;

	modifiers = 0;
	buttonState = 0;
}

WebViewProxy::~WebViewProxy()
{
	if(asyncRenderBuffer)
		delete asyncRenderBuffer;

	delete navController;
	delete canvas;
	delete renderBuffer;

	LOG(INFO) << "A WebViewProxy has been destroyed.";
}

void WebViewProxy::asyncStartup()
{
  // inspired by Chromium\src\webkit\tools\test_shell\webview_host_win.cc

	view = ::WebView::create(this);

	WebPreferences *web_prefs = new WebPreferences();
	//mgdesign, specific config for embedded
	web_prefs->experimental_webgl_enabled = true;
	//mgdesign, chrome v5:
	//web_prefs->allow_file_access_from_file_urls = true;
	web_prefs->allow_universal_access_from_file_urls = true;
	web_prefs->allow_scripts_to_close_windows = true;
	web_prefs->developer_extras_enabled = true;
	web_prefs->web_security_enabled = false;
	// --
	web_prefs->Apply(view);

	view->initializeMainFrame(this);

  //

	view->resize(WebKit::WebSize(width, height));

	clientObject = new ClientObject(parent);

	if(enableAsyncRendering)
	{
		asyncRenderTimer.Start(base::TimeDelta::FromMilliseconds(1000 / maxAsyncRenderPerSec), this, &WebViewProxy::paintAsyncRenderBuffer);
	}

	LOG(INFO) << "A new WebViewProxy has been created.";
}

void WebViewProxy::asyncShutdown()
{
	if(enableAsyncRendering)
		asyncRenderTimer.Stop();

	closeAllPopups();

	//view->GetMainFrame()->CallJSGC();
	view->mainFrame()->collectGarbage();
//	view->GetMainFrame()->CallJSGC();
	view->mainFrame()->collectGarbage();

	delete clientObject;

//	view->Close();
	view->close();

	LOG(INFO) << "In WebViewProxy::asyncShutdown";

	parent->setFinishShutdown();
	parent = 0;
}	
/*
std::string WebViewProxy::GetResourceDescription(uint32 identifier) {
  ResourceMap::iterator it = resource_identifier_map_.find(identifier);
  return it != resource_identifier_map_.end() ? it->second : "<unknown>";
}
*/

void WebViewProxy::loadURL(const std::string& url, const std::wstring& frameName)
{
	std::wstring frame = WebStringToWString(view->mainFrame()->name());
	if (frameName.length())
		if (view->findFrameByName(frameName))
			frame = frameName;

	navController->LoadEntry(new NavigationEntry(nextPageID++, GURL(url), std::wstring(), frame));
}

void WebViewProxy::loadHTML(const std::string& html, const std::wstring& frameName)
{
	std::string baseDirectory = Awesomium::WebCore::Get().getBaseDirectory();

	std::wstring frame = WebStringToWString(view->mainFrame()->name());
	if(frameName.length())
		if(view->findFrameByName(frameName))
			frame = frameName;

	navController->LoadEntry(new NavigationEntry(nextPageID++, html, GURL("file:///" + baseDirectory), frame));
}

void WebViewProxy::loadFile(const std::string& file, const std::wstring& frameName)
{
	loadURL("file:///" + Awesomium::WebCore::Get().getBaseDirectory() + file, frameName);
}

void WebViewProxy::goToHistoryOffset(int offset)
{
	navController->GoToOffset(offset);
}

void WebViewProxy::refresh()
{
	navController->Reload();
}

void WebViewProxy::executeJavascript(const std::string& javascript, const std::wstring& frameName)
{
  executeJavascriptWithSignal(javascript, frameName, NULL);
}

void WebViewProxy::executeJavascriptWithSignal(const std::string& javascript, const std::wstring& frameName, base::WaitableEvent* doneEvent)
{
	WebFrame* frame = view->mainFrame();
	if (frameName.length())
		frame = view->findFrameByName(frameName);

	if (frame)
  {
	  WebKit::WebURLRequest request(GURL("javascript:" + javascript + ";void(0);"));
	  frame->loadRequest(request);
  }

  if (doneEvent != NULL)
    doneEvent->Signal();
}

void WebViewProxy::setProperty(const std::string& name, const Awesomium::JSValue& value)
{
	clientObject->setProperty(name, value);
}

void WebViewProxy::setCallback(const std::string& name)
{
	clientObject->setCallback(name);
}

void WebViewProxy::getNPObjectProperty(NPObject* object, NPIdentifier propertyName, NPVariant* result, base::WaitableEvent* doneEvent)
{
  NPP npp = NULL;
  WebKit::WebBindings::getProperty(npp, object, propertyName, result);
  doneEvent->Signal();
}

void WebViewProxy::invokeNPObject(NPObject* object, NPIdentifier methodName, const NPVariant* args, uint32_t count, NPVariant* result, base::WaitableEvent* doneEvent)
{
  NPP npp = NULL;
  WebKit::WebBindings::invoke(npp, object, methodName, args, count, result);
  doneEvent->Signal();
}

void WebViewProxy::invokeNPObjectDefault(NPObject* object, const NPVariant* args, uint32_t count, NPVariant* result, base::WaitableEvent* doneEvent)
{
  NPP npp = NULL;
  WebKit::WebBindings::invokeDefault(npp, object, args, count, result);
  doneEvent->Signal();
}

WebKit::WebRect WebViewProxy::paintRenderBuffer()
{
  const gfx::Rect clientRect(width, height);
  gfx::Rect invalidArea = dirtyArea.Intersect( clientRect );

  if (invalidArea.IsEmpty() && !isPopupsDirty)
    return gfx::Rect();

  // some layout may be pending, as it could change the 'dirtyArea', do it now and update the dirtyArea

  view->layout();
  invalidArea = dirtyArea.Intersect(clientRect);

  if (transparencyMode == Awesomium::WebView::TM_CANVAS_ALPHA_CHANNEL)
  {
    // clear the invalid area, as the background is transparent and, thus, it is never painted

    const SkBitmap& sourceBitmap = canvas->getTopPlatformDevice().accessBitmap(true);

    SkIRect clearIRect;
    clearIRect.set(invalidArea.x(), invalidArea.y(), invalidArea.right(), invalidArea.bottom());

    SkRect clearRect;
    clearRect.set(clearIRect);

    SkPaint clearPaint;
    clearPaint.setARGB(0,0,0,0);
    clearPaint.setXfermodeMode(SkXfermode::kSrc_Mode);

    SkCanvas canvas(sourceBitmap);
    canvas.drawRect(clearRect, clearPaint);
  }

  if (transparencyMode == Awesomium::WebView::TM_DEDUCE_ALPHA_CHANNEL)
	{
    paintEstimateAlpha(invalidArea);
	}
	else
	{
    layoutPaintCanvas(invalidArea);
    copyCanvasToRenderBuffer(invalidArea);
	}

	if (!popups.empty())
	{
		WebKit::WebRect tempRect;

    bool forceOpaque = (transparencyMode == Awesomium::WebView::TM_OPAQUE);

    for(std::vector<PopupWidget*>::iterator i = popups.begin(); i != popups.end(); i++)
		{
			tempRect = (*i)->windowRect();
			if(!tempRect.isEmpty())
			{
				(*i)->renderToWebView(*renderBuffer, forceOpaque);
				invalidArea = invalidArea.Union(gfx::Rect(tempRect));
			}
		}

		invalidArea = gfx::Rect(width, height).Intersect(invalidArea);
	}
  
	isPopupsDirty = false;

	dirtyArea = gfx::Rect();

	return WebKit::WebRect(invalidArea);
}

void WebViewProxy::layoutPaintCanvas(const gfx::Rect& invalidArea)
{
  view->layout();
	view->paint(SkiaCanvasToWebCanvas(canvas), invalidArea);
}

void WebViewProxy::copyCanvasToRenderBuffer(const gfx::Rect& invalidArea)
{
	const SkBitmap& sourceBitmap = canvas->getTopPlatformDevice().accessBitmap(false);
	SkAutoLockPixels sourceBitmapLock(sourceBitmap);

	renderBuffer->copyAreaFrom(
    invalidArea
  , (unsigned char*)sourceBitmap.getPixels() + invalidArea.y()*sourceBitmap.rowBytes() + invalidArea.x()*4
  , sourceBitmap.rowBytes()
  );
}

void WebViewProxy::paintEstimateAlpha(const gfx::Rect& invalidArea)
{
  executeJavascript("document.body.style.backgroundColor = '#000000'");

  layoutPaintCanvas(invalidArea);
  copyCanvasToRenderBuffer(invalidArea);

	executeJavascript("document.body.style.backgroundColor = '#FFFFFF'");

  layoutPaintCanvas(invalidArea);

	{
    // estimate alpha channel from renderBuffer (black background) and canvas (white background) pixels differences

		const SkBitmap& sourceBitmap = canvas->getTopPlatformDevice().accessBitmap(false);
		SkAutoLockPixels sourceBitmapLock(sourceBitmap);

		unsigned char* buffer = (unsigned char*)sourceBitmap.getPixels();
		unsigned char* active_buffer = renderBuffer->buffer;

    int const invalidArea_width = invalidArea.width();
		int rowOffset = invalidArea.y() * renderBuffer->rowSpan + (invalidArea.x() * 4);

		for(int row = 0; row < invalidArea.height(); row++)
		{
      int offset = rowOffset;

			for(int col = 0; col < invalidArea_width; col++)
			{
				active_buffer[offset + 3] = 255 - (buffer[offset] - active_buffer[offset]);
        offset += 4;
			}

      rowOffset += renderBuffer->rowSpan;
		}
	}
}

void WebViewProxy::copyAsyncRenderBuffer(unsigned char* destination, int destRowSpan, Awesomium::WebView::RenderCopyMode copyMode, Awesomium::Rect* renderedRect)
{
  if (destRowSpan == -1)
    destRowSpan = width * 4;

  AutoLock auto_renderBufferLock( asyncRenderBufferLock );

  bool convertToRGBA = Awesomium::WebCore::GetPointer()->getPixelFormat() == Awesomium::PF_RGBA;

  if (renderedRect != 0)
  {
	  *renderedRect = Awesomium::Rect(asyncUpdatedArea.x(), asyncUpdatedArea.y(), asyncUpdatedArea.width(), asyncUpdatedArea.height());
  }

  switch (copyMode)
  {
  case Awesomium::WebView::RCM_UPDATE_ALL:
    asyncRenderBuffer->copyTo(destination, destRowSpan, convertToRGBA);
    break;

  case Awesomium::WebView::RCM_UPDATE_DIRTY:
    asyncRenderBuffer->copyAreaTo(asyncUpdatedArea, asyncUpdatedArea.x(), asyncUpdatedArea.y(), destination, destRowSpan, convertToRGBA);
    break;

  case Awesomium::WebView::RCM_DIRTY_ONLY:
    asyncRenderBuffer->copyAreaTo(asyncUpdatedArea, 0, 0, destination, asyncUpdatedArea.width()*4, convertToRGBA);
    break;
  }

	if(isAsyncRenderDirty)
	{
		parent->setAsyncDirty(false);
		isAsyncRenderDirty = false;
    asyncUpdatedArea = gfx::Rect();
	}
}

void WebViewProxy::paintAsyncRenderBuffer()
{
  assert( enableAsyncRendering );

	gfx::Rect invalidArea = paintRenderBuffer();

  if (invalidArea.IsEmpty())
    return;

  // fill asyncRenderBuffer, and associated asyncUpdatedArea

  AutoLock auto_renderBufferLock( asyncRenderBufferLock );

  asyncRenderBuffer->copyAreaFrom(*renderBuffer, invalidArea);

	isAsyncRenderDirty = true;
  asyncUpdatedArea = asyncUpdatedArea.Union(invalidArea);

  // TODO setAsyncDirty uses a full fledged Lock - couldn't it be simplified ? it's only a 'bool'
	parent->setAsyncDirty(true);
}

void WebViewProxy::renderSync(unsigned char* destination, int destRowSpan, Awesomium::WebView::RenderCopyMode copyMode, Awesomium::Rect* renderedRect)
{
  if (destRowSpan == -1)
    destRowSpan = width * 4;

	gfx::Rect invalidArea = paintRenderBuffer();

  bool convertToRGBA = Awesomium::WebCore::GetPointer()->getPixelFormat() == Awesomium::PF_RGBA;
  switch (copyMode)
  {
  case Awesomium::WebView::RCM_UPDATE_ALL:
    renderBuffer->copyTo(destination, destRowSpan, convertToRGBA);
    break;

  case Awesomium::WebView::RCM_UPDATE_DIRTY:
    renderBuffer->copyAreaTo(invalidArea, invalidArea.x(), invalidArea.y(), destination, renderBuffer->width*4, convertToRGBA);
    break;

  case Awesomium::WebView::RCM_DIRTY_ONLY:
    renderBuffer->copyAreaTo(invalidArea, 0, 0, destination, invalidArea.width()*4, convertToRGBA);
    break;
  }

	if(renderedRect)
		*renderedRect = Awesomium::Rect(invalidArea.x(), invalidArea.y(), invalidArea.width(), invalidArea.height());

	parent->setFinishRender();
}

void WebViewProxy::syncLayout(base::WaitableEvent* event_)
{
  view->layout();

  if (event_ != NULL)
    event_->Signal();
}

void WebViewProxy::injectMouseMove(int x, int y)
{
	mouseX = x;
	mouseY = y;

	handleMouseEvent(WebKit::WebInputEvent::MouseMove, 0);
}

void WebViewProxy::injectMouseDown(short mouseButtonID)
{
	handleMouseEvent(WebKit::WebInputEvent::MouseDown, mouseButtonID);
}

void WebViewProxy::injectMouseUp(short mouseButtonID)
{
	handleMouseEvent(WebKit::WebInputEvent::MouseUp, mouseButtonID);
}

template <class EventType>
void WebViewProxy::initializeWebEvent(EventType &event, WebKit::WebInputEvent::Type type) {
	memset(&event, 0, sizeof(EventType)); // in case the definition changes.
	event.type = type;
	event.size = sizeof(EventType);
	event.modifiers = modifiers;
#if defined(_WIN32)
	event.timeStampSeconds = GetTickCount() / 1000.0;
#else
	{
		timeval tv;
		gettimeofday(&tv,NULL);
		double timestamp = ((double)tv.tv_usec)/10000000.0;
		timestamp += tv.tv_sec;
		event.timeStampSeconds = timestamp;
	}
#endif
}

void WebViewProxy::injectMouseWheel(int scrollAmountX, int scrollAmountY)
{
	WebKit::WebMouseWheelEvent event;
	initializeWebEvent(event, WebKit::WebInputEvent::MouseWheel);
	event.x = mouseX;
	event.y = mouseY;
	event.windowX = mouseX; // PRHFIXME: Window vs Global position?
	event.windowY = mouseY;
	event.globalX = mouseX;
	event.globalY = mouseY;
	event.button = WebKit::WebMouseEvent::ButtonNone;
	event.deltaX = float(scrollAmountX); // PRHFIXME: want x and y scroll.
	event.deltaY = float(scrollAmountY);
	event.wheelTicksX = float(scrollAmountX); // PRHFIXME: want x and y scroll.
	event.wheelTicksY = float(scrollAmountY);
	event.scrollByPage = false;

	view->handleInputEvent(event);
}

void WebViewProxy::injectKeyEvent(bool press, int modifiers, int windowsCode, int nativeCode) {
	WebKit::WebKeyboardEvent event;
	initializeWebEvent(event, press?WebKit::WebInputEvent::RawKeyDown:WebKit::WebInputEvent::KeyUp); 
	event.windowsKeyCode = windowsCode;
	event.nativeKeyCode = nativeCode;
	event.text[0]=0;
	event.unmodifiedText[0]=0;
	event.isSystemKey = !!(modifiers & Awesomium::SYSTEM_KEY);

	event.modifiers=0;
	if (modifiers & Awesomium::ALT_MOD)
		event.modifiers |= WebKit::WebInputEvent::AltKey;
	if (modifiers & Awesomium::CONTROL_MOD)
		event.modifiers |= WebKit::WebInputEvent::ControlKey;
	if (modifiers & Awesomium::SHIFT_MOD)
		event.modifiers |= WebKit::WebInputEvent::ShiftKey;
	if (modifiers & Awesomium::META_MOD)
		event.modifiers |= WebKit::WebInputEvent::MetaKey;
	if (modifiers & Awesomium::KEYPAD_KEY)
		event.modifiers |= WebKit::WebInputEvent::IsKeyPad;
	if (modifiers & Awesomium::AUTOREPEAT_KEY)
		event.modifiers |= WebKit::WebInputEvent::IsAutoRepeat;

	event.setKeyIdentifierFromWindowsKeyCode();

	view->handleInputEvent(event);

	// keep track of persistent modifiers.
	this->modifiers = modifiers & (Awesomium::SHIFT_MOD|Awesomium::CONTROL_MOD|Awesomium::ALT_MOD|Awesomium::META_MOD);
}
void WebViewProxy::injectTextEvent(string16 text) {
	// generate one of these events for each lengthCap chunks.
	// 1 less because we need to null terminate.
	const size_t lengthCap = WebKit::WebKeyboardEvent::textLengthCap-1;
	WebKit::WebKeyboardEvent event;
	initializeWebEvent(event, WebKit::WebInputEvent::Char);
	event.isSystemKey = false;
	event.windowsKeyCode = 0;
	event.nativeKeyCode = 0;
	event.keyIdentifier[0]=0;
	size_t i;
	while (text.size() > lengthCap) {

	}
	for (i = 0; i + lengthCap < text.size(); i+=lengthCap) {
		memcpy(event.text, text.data()+i, lengthCap*sizeof(WebKit::WebUChar));
		event.text[lengthCap]=0;
		memcpy(event.unmodifiedText, text.data()+i, lengthCap*sizeof(WebKit::WebUChar));
		event.unmodifiedText[lengthCap]=0;
		view->handleInputEvent(event);
	}
	if (i < text.size()) {
		assert(text.size()-i <= lengthCap);
		memcpy(event.unmodifiedText, text.data()+i, (text.size()-i)*sizeof(WebKit::WebUChar));
		memcpy(event.text, text.data()+i, (text.size()-i)*sizeof(WebKit::WebUChar));
		event.text[text.size()-i]=0;
		event.unmodifiedText[text.size()-i]=0;
		view->handleInputEvent(event);
	}
}

#if defined(_WIN32)
void WebViewProxy::injectKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{

	WebKit::WebKeyboardEvent event (WebKit::WebInputEventFactory::keyboardEvent(hwnd, message, wparam, lparam));
	view->handleInputEvent(event);

	checkKeyboardFocus();
}

#elif defined(__APPLE__)
void WebViewProxy::injectKeyboardEvent(NSEvent* keyboardEvent)
{
	WebKit::WebKeyboardEvent event (WebKit::WebInputEventFactory::keyboardEvent(keyboardEvent));
	view->handleInputEvent(event);
}
#endif

void WebViewProxy::cut()
{
    WebKit::WebUChar cmd[] = {'C','u','t'};
//	view->GetFocusedFrame()->executeCommand(WebKit::WebString(cmd, 3));
	view->focusedFrame()->executeCommand(WebKit::WebString(cmd, 3));
}

void WebViewProxy::copy()
{
    WebKit::WebUChar cmd[] = {'C','o','p','y'};
//	view->GetFocusedFrame()->executeCommand(WebKit::WebString(cmd, 4));
	view->focusedFrame()->executeCommand(WebKit::WebString(cmd, 4));
}

void WebViewProxy::paste()
{
    WebKit::WebUChar cmd[] = {'P','a','s','t','e'};
//	view->GetFocusedFrame()->executeCommand(WebKit::WebString(cmd, 5));
	view->focusedFrame()->executeCommand(WebKit::WebString(cmd, 5));
}

void WebViewProxy::selectAll()
{
    WebKit::WebUChar cmd[] = {'S','e','l','e','c','t','A','l','l'};
//	view->GetFocusedFrame()->executeCommand(WebKit::WebString(cmd, 9));
	view->focusedFrame()->executeCommand(WebKit::WebString(cmd, 9));
}

void WebViewProxy::deselectAll()
{
    WebKit::WebUChar cmd[] = {'U','n','s','e','l','e','c','t'};
//	view->GetFocusedFrame()->executeCommand(WebKit::WebString(cmd, 8));
	view->focusedFrame()->executeCommand(WebKit::WebString(cmd, 8));
}

void WebViewProxy::getContentAsText(std::wstring* result, int maxChars)
{
	//WebFrame* frame = view->GetMainFrame();
	WebFrame* frame = view->mainFrame();

	if(frame) {
        WebKit::WebString text (frame->contentAsText(maxChars));
        *result = WebStringToWString(text);
    }
	parent->setFinishGetContentText();
}



void WebViewProxy::didCreateScriptContext()
{
}

// The original version of this is WindowScriptObjectAvailable, below. This
// is a Chrome-specific version that serves the same purpose, but has been
// renamed since we haven't implemented WebScriptObject.  Our embedding
// implementation binds native objects to the window via the webframe instead.
// TODO(pamg): If we do implement WebScriptObject, we may wish to switch to
// using the original version of this function.
void WebViewProxy::didClearWindowObject(WebFrame* frame)
{
		clientObject->BindToJavascript(frame, L"Client");
		clientObject->initInternalCallbacks();
}

void WebViewProxy::zoomIn()
{
	//mgdesign, chrome v4:
	view->zoomIn(false);
	//mgdesign, chrome v5:
	//view->setZoomLevel(false,view->zoomLevel()+1);
	invalidatePopups();
}


void WebViewProxy::zoomOut()
{
	//mgdesign, chrome v4:
	view->zoomOut(false);
	//mgdesign, chrome v5:	
	//view->setZoomLevel(false,view->zoomLevel()-1);
	invalidatePopups();
}

void WebViewProxy::resetZoom()
{
	//mgdesign, chrome v4:
	view->zoomDefault();
	//mgdesign, chrome v5
	//view->setZoomLevel(false,0);
	invalidatePopups();
}

void WebViewProxy::resize(int width, int height)
{
	delete renderBuffer;
	delete canvas;

	this->width = width;
	this->height = height;

	renderBuffer = new Awesomium::RenderBuffer(width, height);
	canvas = new skia::PlatformCanvas(width, height, true);

	if(asyncRenderBuffer)
	{
		delete asyncRenderBuffer;
		asyncRenderBuffer = new Awesomium::RenderBuffer(width, height);
	}

	view->resize(gfx::Size(width, height));

	invalidatePopups();

	if(enableAsyncRendering)
  {
    // force a redraw now
		paintAsyncRenderBuffer();
  }

	parent->setFinishResize();
}

void WebViewProxy::setTransparencyMode(Awesomium::WebView::TransparencyMode mode)
{
  if (mode == transparencyMode)
    return;

  // instruct WebKit to handle or not transparency

  view->setIsTransparent(mode == Awesomium::WebView::TM_CANVAS_ALPHA_CHANNEL);

  // instruct draw canvas to have an alpha channel

  bool const is_opaque_canvas = (transparencyMode != Awesomium::WebView::TM_CANVAS_ALPHA_CHANNEL);
  
  delete canvas;
	canvas = new skia::PlatformCanvas(width, height, is_opaque_canvas);

  //

  transparencyMode = mode;

  didInvalidateRect(WebKit::WebRect(0, 0, width, height));
}

void WebViewProxy::getTransparencyMode(Awesomium::WebView::TransparencyMode* result)
{
  *result = transparencyMode;

	parent->setFinishGetTransparencyMode();
}

void WebViewProxy::invalidatePopups()
{
	if(parent && !isPopupsDirty)
		parent->setDirty();

	isPopupsDirty = true;
}

// ::WebView additions -------------------------------------------------------

// This method is called to create a new ::WebView.  The ::WebView should not be
// made visible until the new ::WebView's Delegate has its Show method called.
// The returned ::WebView pointer is assumed to be owned by the host window,
// and the caller of CreateWebView should not release the given ::WebView.
// user_gesture is true if a user action initiated this call.
/*
::WebView* WebViewProxy::CreateWebView(::WebView* webview, bool user_gesture, const GURL& creator_url)
{

// Usually a new WebView is requested to be created when a user clicks on a link
	// that has target='_blank'. For our context, it's better to open the link
// in the same frame and so we deny the creation of the new WebView and
// navigate to the last URL that was hovered over.


	if(!lastTargetURL.is_empty())
//		MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebViewProxy::loadURL, lastTargetURL.spec(), WebStringToWString(view->GetFocusedFrame()->name()), std::string(), std::string()));
		MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebViewProxy::loadURL, lastTargetURL.spec(), WebStringToWString(view->focusedFrame()->name()), std::string(), std::string()));

	return NULL;
}
*/

WebView* WebViewProxy::createView(WebFrame* creator) 
{
	Awesomium::WebCore::Get().queueEvent(new WebViewEvents::CreateNewWebView(parent));
  return NULL;
}

WebWidget* WebViewProxy::createPopupMenu(bool activatable)
{
	PopupWidget* popup = new PopupWidget(this);
	popups.push_back(popup);
	return popup->getWidget();

}
WebWidget* WebViewProxy::createPopupMenu(const WebPopupMenuInfo&)
{
	WebWidget* wid = createPopupMenu(true);
	//popup_info.itemHeight*popup_info.items.size();
	//wid->resize(WebKit::WebSize(width, height));
	wid->setFocus(true);
	wid->layout();
	return wid;
}

WebKit::WebMediaPlayer* WebViewProxy::createWebMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client)
{
  scoped_refptr<media::FilterFactoryCollection> factory =
      new media::FilterFactoryCollection();
  // Add in any custom filter factories first.

#ifndef DISABLE_AUDIO
    // Add the chrome specific audio renderer.
    //factory->AddFactory(   media::AudioRendererImpl::CreateFilterFactory(audio_message_filter()));
#endif


  // TODO(hclam): obtain the following parameters from |client|.
  webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory =
      new webkit_glue::MediaResourceLoaderBridgeFactory(
          GURL::EmptyGURL(),  // referrer
          "null",             // frame origin
          "null",             // main_frame_origin
          base::GetCurrentProcId(),
          appcache::kNoCacheId,
          0);//routing_id

  // A simple data source that keeps all data in memory.
  media::FilterFactory* simple_data_source_factory =  webkit_glue::SimpleDataSource::CreateFactory(MessageLoop::current(),bridge_factory);
  // A sophisticated data source that does memory caching.
  media::FilterFactory* buffered_data_source_factory = webkit_glue::BufferedDataSource::CreateFactory(MessageLoop::current(),bridge_factory);
  factory->AddFactory(buffered_data_source_factory);
  factory->AddFactory(simple_data_source_factory);
  webkit_glue::WebMediaPlayerImpl *impl = new webkit_glue::WebMediaPlayerImpl(client, factory);
  return impl;
}


WebKit::WebPlugin* WebViewProxy::createPlugin(WebFrame* frame, const WebPluginParams& params) {
  return new webkit_glue::WebPluginImpl(frame, params, AsWeakPtr());
}



bool WebViewProxy::allowPlugins(WebFrame* frame, bool enabled_per_settings) {
  return enabled_per_settings; // && shell_->allow_plugins();
}

// This method is called to create a WebPluginDelegate implementation when a
// new plugin is instanced.  See webkit_glue::CreateWebPluginDelegateHelper
// for a default WebPluginDelegate implementation.
webkit_glue::WebPluginDelegate* WebViewProxy::CreatePluginDelegate(const GURL& url, const std::string& mime_type,  std::string* actual_mime_type)
{
	
	if(!Awesomium::WebCore::Get().arePluginsEnabled())
		return 0;

  bool allow_wildcard = true;

  ::WebPluginInfo info;
	if(!NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, allow_wildcard, &info, actual_mime_type))
		return 0;

	if(actual_mime_type && !actual_mime_type->empty())
    //return WebPluginDelegateImpl::Create(info.path, *actual_mime_type, hwnd);
		return WindowlessPlugin::Create(info.path, *actual_mime_type);
	else
    //return WebPluginDelegateImpl::Create(info.path, mime_type, hwnd);
		return WindowlessPlugin::Create(info.path, mime_type);
		
	return NULL;
}


// Called when a windowed plugin is created.
// Lets the view delegate create anything it is using to wrap the plugin.
void WebViewProxy::CreatedPluginWindow(  gfx::PluginWindowHandle handle)
{
	// not yet implemented
	return;
}

// Called when a windowed plugin is closing.
// Lets the view delegate shut down anything it is using to wrap the plugin.
void WebViewProxy::WillDestroyPluginWindow( gfx::PluginWindowHandle handle)
{
	// not yet implemented
	return;
}


// Keeps track of the necessary window move for a plugin window that resulted
// from a scroll operation.  That way, all plugin windows can be moved at the
// same time as each other and the page.
void WebViewProxy::DidMovePlugin(const webkit_glue::WebPluginGeometry& move)
{
	// not yet implemented
	return;
}


// Notifies the parent view that a load has begun.
void WebViewProxy::DidStartLoadingForPlugin(){	
	//Awesomium::WebCore::Get()->UpdateNavigationControls();
}
// Notifies the parent view that all loads are finished.
void WebViewProxy::DidStopLoadingForPlugin(){	
  //shell_->UpdateNavigationControls();	
}


// Asks the browser to show a modal HTML dialog.  The dialog is passed the
// given arguments as a JSON string, and returns its result as a JSON string
// through json_retval.
void WebViewProxy::ShowModalHTMLDialogForPlugin( const GURL& url,  const gfx::Size& size,  const std::string& json_arguments,  std::string* json_retval)
{
	return;
}

// mgdesign, added for chrome v4, remove in v5 ?
WebCookieJar* WebViewProxy::GetCookieJar() {
	return WebKit::webKitClient()->cookieJar();
}



// This method is called to open a URL in the specified manner.
void WebViewProxy::loadURLExternally( WebFrame* frame, const WebURLRequest& req, WebNavigationPolicy p)
{
		return;
}

// FrameLoaderClient -------------------------------------------------------

// Notifies the delegate that a load has begun.
void WebViewProxy::didStartLoading() 
{
//	Awesomium::WebCore::Get().queueEvent(new WebViewEvents::BeginLoad(parent));
}

// Notifies the delegate that all loads are finished.
void WebViewProxy::didStopLoading()
{
	Awesomium::WebCore::Get().queueEvent(new WebViewEvents::FinishLoad(parent));

	didInvalidateRect(WebKit::WebRect(0, 0, width, height));
	invalidatePopups();
}


// PolicyDelegate ----------------------------------------------------------

// This method is called to notify the delegate, and let it modify a
// proposed navigation. It will be called before loading starts, and
// on every redirect.
//
// disposition specifies what should normally happen for this
// navigation (open in current tab, start a new tab, start a new
// window, etc).  This method can return an altered disposition, and
// take any additional separate action it wants to.
//
// is_redirect is true if this is a redirect rather than user action.
//WebKit::WebNavigationPolicy WebViewProxy::PolicyForNavigationAction(::WebView* webview,WebFrame* frame,const WebKit::WebURLRequest& request,WebKit::WebNavigationType type,WebKit::WebNavigationPolicy default_policy,bool is_redirect)
WebKit::WebNavigationPolicy WebViewProxy::decidePolicyForNavigation(WebFrame* frame, const WebKit::WebURLRequest& request, WebKit::WebNavigationType n,const WebKit::WebNode& originatingNode,WebKit::WebNavigationPolicy defaultPolicy, bool isRedirect)
{
	Awesomium::WebCore::Get().queueEvent(new WebViewEvents::BeginNavigate(parent, request.url().spec(), WebStringToWString(frame->name())));

	  // TODO - implement whitelisting/blackliting

	return defaultPolicy;
}

// FrameLoadDelegate -------------------------------------------------------

// Notifies the delegate that the provisional load of a specified frame in a
// given ::WebView has started. By the time the provisional load for a frame has
// started, we know whether or not the current load is due to a client
// redirect or not, so we pass this information through to allow us to set
// the referrer properly in those cases. The consumed_client_redirect_src is
// an empty invalid GURL in other cases.
void WebViewProxy::didStartProvisionalLoad(WebFrame* frame)
{
	WebDataSource* dataSource = frame->provisionalDataSource();

	if(dataSource)
	{
		std::string url = dataSource->request().url().spec();
		int statusCode = dataSource->response().httpStatusCode();
		WebKit::WebString mimeType = dataSource->response().mimeType();
		// PRHFIXME: Do we do anything with these?
	}
}

// Called when a provisional load is redirected (see GetProvisionalDataSource
// for more info on provisional loads). This happens when the server sends
// back any type of redirect HTTP response.
//
// The redirect information can be retrieved from the provisional data
// source's redirect chain, which will be updated prior to this callback.
// The last element in that vector will be the new URL (which will be the
// same as the provisional data source's current URL), and the next-to-last
// element will be the referring URL.
void  WebViewProxy::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
{
	return;
}

//  @method webView:didFailProvisionalLoadWithError:forFrame:
//  @abstract Notifies the delegate that the provisional load has failed
//  @param webView The ::WebView sending the message
//  @param error The error that occurred
//  @param frame The frame for which the error occurred
//  @discussion This method is called after the provisional data source has
//  failed to load.  The frame will continue to display the contents of the
//  committed data source if there is one.
void WebViewProxy::didFailProvisionalLoad(WebFrame* frame, const WebURLError& e)
{
		return;
}

// Notifies the delegate that the load has changed from provisional to
// committed. This method is called after the provisional data source has
// become the committed data source.
//
// In some cases, a single load may be committed more than once. This
// happens in the case of multipart/x-mixed-replace, also known as "server
// push". In this case, a single location change leads to multiple documents
// that are loaded in sequence. When this happens, a new commit will be sent
// for each document.
//
// The "is_new_navigation" flag will be true when a new session history entry
// was created for the load.  The frame's GetHistoryState method can be used
// to get the corresponding session history state.
void WebViewProxy::didCommitProvisionalLoad(WebFrame* frame, bool isNewNavigation)
{
	WebDataSource* dataSource = frame->dataSource();

	if(dataSource)
	{
		std::string url = dataSource->request().url().spec();
		int statusCode = dataSource->response().httpStatusCode();
		std::wstring mimeType (WebStringToWString(dataSource->response().mimeType()));

		LOG(INFO) << "Committed Load for Frame. URL: " << url << ", Status Code: " << statusCode << ", Mime-Type: " << mimeType << ", Frame Name: " << frame->name();

		Awesomium::WebCore::Get().queueEvent(new WebViewEvents::BeginLoad(parent, url, WebStringToWString(frame->name()), statusCode, mimeType));

		std::string responseFile;
		Awesomium::WebCore::Get().getCustomResponsePage(statusCode, responseFile);
		
		if(responseFile.length())
			MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebViewProxy::loadFile, responseFile, WebStringToWString(frame->name())));

		if(WebStringToWString(frame->name()).substr(0, 5) == L"OIFW_")
			MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebViewProxy::overrideIFrameWindow, WebStringToWString(frame->name())));
	}

	updateForCommittedLoad(frame, isNewNavigation);
}

//  @method webView:didReceiveTitle:forFrame:
//  @abstract Notifies the delegate that the page title for a frame has been received
//  @param webView The ::WebView sending the message
//  @param title The new page title
//  @param frame The frame for which the title has been received
//  @discussion The title may update during loading; clients should be prepared for this.
//  - (void)webView:(::WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame;
void WebViewProxy::didReceiveTitle(WebFrame* frame, const std::wstring& title)
{
	Awesomium::WebCore::Get().queueEvent(new WebViewEvents::ReceiveTitle(parent, title, WebStringToWString(frame->name())));
}

//
//  @method webView:didFinishLoadForFrame:
//  @abstract Notifies the delegate that the committed load of a frame has completed
//  @param webView The ::WebView sending the message
//  @param frame The frame that finished loading
//  @discussion This method is called after the committed data source of a frame has successfully loaded
//  and will only be called when all subresources such as images and stylesheets are done loading.
//  Plug-In content and JavaScript-requested loads may occur after this method is called.
//  - (void)webView:(::WebView *)sender didFinishLoadForFrame:(WebFrame *)frame;
void WebViewProxy::didFinishLoad(WebFrame*)
{
	return;
}

//
//  @method webView:didFailLoadWithError:forFrame:
//  @abstract Notifies the delegate that the committed load of a frame has failed
//  @param webView The ::WebView sending the message
//  @param error The error that occurred
//  @param frame The frame that failed to load
//  @discussion This method is called after a data source has committed but failed to completely load.
//  - (void)webView:(::WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame;
void  WebViewProxy::didFailLoad(WebFrame*, const WebURLError&)
{
}

// Notifies the delegate of a DOMContentLoaded event.
// This is called when the html resource has been loaded, but
// not necessarily all subresources (images, stylesheets). So, this is called
// before DidFinishLoadForFrame.
void WebViewProxy::didFinishDocumentLoad(WebFrame* frame)
{
}

// This method is called when we load a resource from an in-memory cache.
// A return value of |false| indicates the load should proceed, but WebCore
// appears to largely ignore the return value.

void WebViewProxy::didLoadResourceFromMemoryCache(WebFrame*, const WebURLRequest&, const WebURLResponse&)
{
	//return false;
	return;
}

// This is called after javascript onload handlers have been fired.
void WebViewProxy::didHandleOnloadEvents(WebFrame*)
{
	return;
}

// This method is called when anchors within a page have been clicked.
// It is very similar to DidCommitLoadForFrame.
void WebViewProxy::didChangeLocationWithinPage(WebFrame* frame, bool isNewNavigation)
{
	updateForCommittedLoad(frame, isNewNavigation);
}

// This is called when the favicon for a frame has been received.
/*
void WebViewProxy::DidReceiveIconForFrame(::WebView* webview, WebFrame* frame)
{
}
*/

// Notifies the delegate that a frame will start a client-side redirect. When
// this function is called, the redirect has not yet been started (it may
// not even be scheduled to happen until some point in the future). When the
// redirect has been cancelled or has succeeded, DidStopClientRedirect will
// be called.
//
// WebKit considers meta refreshes, and setting document.location (regardless
// of when called) as client redirects (possibly among others).
//
// This function is intended to continue progress feedback while a
// client-side redirect is pending. Watch out: WebKit seems to call us twice
// for client redirects, resulting in two calls of this function.
void WebViewProxy::willPerformClientRedirect( WebFrame*, const WebURL& from, const WebURL& to,   double interval, double fireTime)
{
	return;
}

// Notifies the delegate that a pending client-side redirect has been
// cancelled (for example, if the frame changes before the timeout) or has
// completed successfully. A client-side redirect is the result of setting
// document.location, for example, as opposed to a server side redirect
// which is the result of HTTP headers (see DidReceiveServerRedirect).
//
// On success, this will be called when the provisional load that the client
// side redirect initiated is committed.
//
// See the implementation of FrameLoader::clientRedirectCancelledOrFinished.
void WebViewProxy::didCancelClientRedirect(WebFrame*)
{
}

bool WebViewProxy::canHandleRequest(WebFrame* frame, const WebURLRequest& request) 
{
  GURL url = request.url();
  // Just reject the scheme used in
  // LayoutTests/http/tests/misc/redirect-to-external-url.html
  return !url.SchemeIs("spaceballs");
}

WebURLError WebViewProxy::cannotHandleRequestError(WebFrame* frame, const WebURLRequest& request) 
{
  WebURLError error;
  // A WebKit layout test expects the following values.
  // unableToImplementPolicyWithError() below prints them.
  error.domain = WebString::fromUTF8("WebKitErrorDomain");
  error.reason = 101;
  error.unreachableURL = request.url();
  return error;
}

WebURLError WebViewProxy::cancelledError(WebFrame* frame, const WebURLRequest& request)
{
	WebURLError error;
  error.domain = WebString::fromUTF8(net::kErrorDomain);
  error.reason = net::ERR_ABORTED;
  error.unreachableURL = request.url();
  return error;
}

void WebViewProxy::unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error) {
  std::string domain = error.domain.utf8();
  printf("Policy delegate: unable to implement policy with error domain '%s', error code %d, in frame '%s'\n",domain.data(), error.reason, frame->name().utf8().data());
}



// Notifies the delegate that the load about to be committed for the specified
// webview and frame was due to a client redirect originating from source URL.
// The information/notification obtained from this method is relevant until
// the next provisional load is started, at which point it becomes obsolete.
//void WebViewProxy::DidCompleteClientRedirect(::WebView* webview, WebFrame* frame, const GURL& source)
void WebViewProxy::didCompleteClientRedirect(WebFrame*, const WebURL& fromURL)
{
	return;
}

//  @method webView:willCloseFrame:
//  @abstract Notifies the delegate that a frame will be closed
//  @param webView The ::WebView sending the message
//  @param frame The frame that will be closed
//  @discussion This method is called right before WebKit is done with the frame
//  and the objects that it contains.
//  - (void)webView:(::WebView *)sender willCloseFrame:(WebFrame *)frame;
void WebViewProxy::willClose(WebFrame* frame)
{
}

// ResourceLoadDelegate ----------------------------------------------------

// Associates the given identifier with the initial resource request.
// Resource load callbacks will use the identifier throughout the life of the
// request.

void WebViewProxy::assignIdentifierToRequest( WebFrame*, unsigned identifier, const WebURLRequest&)
{
	return;
}

// Notifies the delegate that a request is about to be sent out, giving the
// delegate the opportunity to modify the request.  Note that request is
// writable here, and changes to the URL, for example, will change the request
// to be made.

void WebViewProxy::willSendRequest( WebFrame*, unsigned identifier, WebURLRequest&, const WebURLResponse& redirectResponse)
{
	return;
}

void WebViewProxy::didReceiveResponse( WebFrame* frame, unsigned identifier, const WebURLResponse& response) {
  //if (shell_->ShouldDumpResourceLoadCallbacks()) {
    //printf("%s - didReceiveResponse %s\n",   GetResourceDescription(identifier).c_str(),   GetResponseDescription(response).c_str());
  //}
	return;
}

void WebViewProxy::didFinishResourceLoad( WebFrame* frame, unsigned identifier) 
{
//  if (shell_->ShouldDumpResourceLoadCallbacks()) {
    //printf("%s - didFinishLoading\n",     GetResourceDescription(identifier).c_str());
 // }
  //resource_identifier_map_.erase(identifier);

	return;
}



// Notifies the delegate that a subresource load has failed, and why.
void WebViewProxy::didFailResourceLoad( WebFrame*, unsigned identifier, const WebURLError&)
{
}

// ChromeClient ------------------------------------------------------------

// Appends a line to the application's error console.  The message contains
// an error description or other information, the line_no provides a line
// number (e.g. for a JavaScript error report), and the source_id contains
// a URL or other description of the source of the message.

void WebViewProxy::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& source_name, unsigned source_line) 
{
  std::ostringstream str;
  str << "\"" << message.text.utf8().data()
      << ",\" source: "
      << source_name.utf8().data()
      << "("
      << source_line
      << ")";

  LOG(INFO) << str.str();

	if(source_line == 1)
		parent->nullifyFutureJSValueCallbacks();

  Awesomium::WebCore::Get().queueEvent(new WebViewEvents::MessageConsole(parent, str.str()));

}


// UIDelegate --------------------------------------------------------------

// Asks the browser to show a modal HTML dialog.  The dialog is passed the
// given arguments as a JSON string, and returns its result as a JSON string
// through json_retval.
void WebViewProxy::ShowModalHTMLDialog(const GURL& url, int width, int height, const std::string& json_arguments, std::string* json_retval)
{
}

// Displays a JavaScript alert panel associated with the given view. Clients
// should visually indicate that this panel comes from JavaScript. The panel
// should have a single OK button.
void WebViewProxy::runModalAlertDialog(     WebFrame*, const WebString& message)
{
}

// Displays a JavaScript confirm panel associated with the given view.
// Clients should visually indicate that this panel comes
// from JavaScript. The panel should have two buttons, e.g. "OK" and
// "Cancel". Returns true if the user hit OK, or false if the user hit Cancel.
bool WebViewProxy::runModalConfirmDialog(  WebFrame*, const WebString& message)
{
	return false;
}

// Displays a JavaScript text input panel associated with the given view.
// Clients should visually indicate that this panel comes from JavaScript.
// The panel should have two buttons, e.g. "OK" and "Cancel", and an area to
// type text. The default_value should appear as the initial text in the
// panel when it is shown. If the user hit OK, returns true and fills result
// with the text in the box.  The value of result is undefined if the user
// hit Cancel.
bool WebViewProxy::runModalPromptDialog( WebFrame*, const WebString& message, const WebString& defaultValue,  WebString* actualValue)
{
	return false;
}

// Displays a "before unload" confirm panel associated with the given view.
// The panel should have two buttons, e.g. "OK" and "Cancel", where OK means
// that the navigation should continue, and Cancel means that the navigation
// should be cancelled, leaving the user on the current page.  Returns true
// if the user hit OK, or false if the user hit Cancel.
bool WebViewProxy::runModalBeforeUnloadDialog(WebFrame*, const WebString& message)
{
	return true;  // OK, continue to navigate away
}

// Called to display a file chooser prompt.  The prompt should be pre-
// populated with the given initial_filename string.  The WebViewDelegate
// will own the WebFileChooserCallback object and is responsible for
// freeing it.
//mgdesign, chrome v5: 
//bool WebViewProxy::runFileChooser(const WebFileChooserParams& wfcp,WebFileChooserCompletion* wfcc)
//mgdesign, chrome v4: 
bool WebViewProxy::runFileChooser(  bool multiSelect, const WebString& title,   const WebString& initialValue, WebFileChooserCompletion*)
{
	//delete file_chooser;
	return false;
}

// @abstract Shows a context menu with commands relevant to a specific
//           element on the current page.
// @param webview The ::WebView sending the delegate method.
// @param node The node(s) the context menu is being invoked on
// @param x The x position of the mouse pointer (relative to the webview)
// @param y The y position of the mouse pointer (relative to the webview)
// @param link_url The absolute URL of the link that contains the node the
// mouse right clicked on
// @param image_url The absolute URL of the image that the mouse right
// clicked on
// @param page_url The URL of the page the mouse right clicked on
// @param frame_url The URL of the subframe the mouse right clicked on
// @param selection_text The raw text of the selection that the mouse right
// clicked on
// @param misspelled_word The editable (possibily) misspelled word
// in the Editor on which dictionary lookup for suggestions will be done.
// @param edit_flags Which edit operations the renderer believes are available
// @param frame_encoding Which indicates the encoding of current focused
// sub frame.

void WebViewProxy::showContextMenu(WebFrame* frame, const WebContextMenuData& wcmd)
{
}

// Starts a drag session with the supplied contextual information.
// webview: The ::WebView sending the delegate method.
// drop_data: a WebDropData struct which should contain all the necessary
// information for dragging data out of the webview.

void WebViewProxy::startDragging(	const WebPoint& from, const WebDragData& wdd, WebDragOperationsMask wdom)
{
	// Immediately cancel drag
	view->dragSourceSystemDragEnded();
}


// Returns the focus to the client.
// reverse: Whether the focus should go to the previous (if true) or the next
// focusable element.

void WebViewProxy::focusNext()
{
}
void WebViewProxy::focusPrevious()
{
}

// Displays JS out-of-memory warning in the infobar

void  WebViewProxy::didExhaustMemoryAvailableForScript(WebFrame*)
{
}

// EditorDelegate ----------------------------------------------------------

// These methods exist primarily to allow a specialized executable to record
// edit events for testing purposes.  Most embedders are not expected to
// override them. In fact, by default these editor delegate methods aren't
// even called by the EditorClient, for performance reasons. To enable them,
// call ::WebView::SetUseEditorDelegate(true) for each ::WebView.

bool WebViewProxy::shouldBeginEditing(const WebRange&) { return true; }
bool WebViewProxy::shouldEndEditing(const WebRange&) { return true; }
bool WebViewProxy::shouldInsertNode(const WebNode&, const WebRange&, WebEditingAction) { return true; }
bool WebViewProxy::shouldInsertText(const WebString&, const WebRange&, WebEditingAction) { return true; }
bool WebViewProxy::shouldChangeSelectedRange(const WebRange& from, const WebRange& to, WebTextAffinity,bool stillSelecting) { return true; }
bool WebViewProxy::shouldDeleteRange(const WebRange&) { return true; }
bool WebViewProxy::shouldApplyStyle(const WebString& style, const WebRange&) { return true; }

bool WebViewProxy::isSmartInsertDeleteEnabled()
{
	return false;
}

void WebViewProxy::didBeginEditing(){ }
void WebViewProxy::didChangeSelection(bool isSelectionEmpty){ }
void WebViewProxy::didChangeContents(){ }
void WebViewProxy::didExecuteCommand(const WebString& commandName){ }
void WebViewProxy::didEndEditing(){ }

// Notification that a user metric has occurred.

// -------------------------------------------------------------------------

// Notification that a request to download an image has completed. |errored|
// indicates if there was a network error. The image is empty if there was
// a network error, the contents of the page couldn't by converted to an
// image, or the response from the host was not 200.
// NOTE: image is empty if the response didn't contain image data.
/*
void WebViewProxy::DidDownloadImage(int id, const GURL& image_url, bool errored, const SkBitmap& image)
{
}
*/

// History Related ---------------------------------------------------------

// Returns the session history entry at a distance |offset| relative to the
// current entry.  Returns NULL on failure.
/*WebKit::WebHistoryItem* WebViewProxy::GetHistoryEntryAtOffset(int offset)
{
	NavigationEntry* entry = static_cast<NavigationEntry*>(navController->GetEntryAtOffset(offset));
	
	if(!entry)
		return NULL;

	return entry->GetHistoryItem();
}
*/

// Asynchronously navigates to the history entry at the given offset.

void WebViewProxy::navigateBackForwardSoon(int offset)
{
	navController->GoToOffset(offset);
}

// Returns how many entries are in the back and forward lists, respectively.
		
int  WebViewProxy::historyBackListCount()
{
	return navController->GetLastCommittedEntryIndex();
}

int  WebViewProxy::historyForwardListCount()
{
	return navController->GetEntryCount() - navController->GetLastCommittedEntryIndex() - 1;
}

// Notification that the form state of an element in the document, scroll
// position, or possibly something else has changed that affects session
// history (HistoryItem). This function will be called frequently, so the
// implementor should not perform intensive operations in this notification.

void WebViewProxy::didUpdateCurrentHistoryItem(WebFrame* frame)
{
	return;
}

// -------------------------------------------------------------------------

namespace {

  // mgdesign: may conflict with an operator != defined in chrome v5
  bool operator!=(const WebString& a, const WebString& b)
  {
    bool const equal_length = a.length() == b.length();
    bool equal_texts;
    if (equal_length)
    {
      equal_texts = std::equal( a.data(), a.data()+a.length(), b.data() );
    }
    else
    {
      equal_texts = false;
    }
    return !equal_texts;
  }

};

// Tell the delegate the tooltip text for the current mouse position.
//void WebViewProxy::SetTooltipText(::WebView* webview, const std::wstring& tooltip_text)
void WebViewProxy::setToolTipText(const WebString& tooltip_text, WebTextDirection hint)
{
	if (curTooltip != tooltip_text)
	{
		Awesomium::WebCore::Get().queueEvent(new WebViewEvents::ChangeTooltip(parent, tooltip_text));
		curTooltip = tooltip_text;
	}
}

// Editor Client -----------------------------------------------------------

// Returns true if the word is spelled correctly. The word may begin or end
// with whitespace or punctuation, so the implementor should be sure to handle
// these cases.
//
// If the word is misspelled (returns false), the given first and last
// indices (inclusive) will be filled with the offsets of the boundary of the
// word within the given buffer. The out pointers must be specified. If the
// word is correctly spelled (returns true), they will be set to (0,0).

void WebViewProxy::spellCheck( const WebString& text, int& misspelledOffset, int& misspelledLength)
{
	misspelledOffset = misspelledLength = 0;
}

// Changes the state of the input method editor.

void WebViewProxy::setInputMethodEnabled(bool enabled)
{
}

// Asks the user to print the page or a specific frame. Called in response to
// a window.print() call.

void WebViewProxy::printPage(WebFrame*)
{
}

/* mgdesign:
void WebViewProxy::WebInspectorOpened(int num_resources)
{
}
*/

// Called when the FrameLoader goes into a state in which a new page load
// will occur.

void WebViewProxy::didReceiveDocumentData( WebFrame* frame, const char* data, size_t length, bool& preventDefault)
{
	return;
}
 
// WebWidgetClient --------------------------------------------------------------------------------------------------



// Called when a region of the WebWidget needs to be re-painted.
void WebViewProxy::didInvalidateRect(const WebKit::WebRect& rect)
{
	gfx::Rect clientRect(width, height);
	dirtyArea = clientRect.Intersect(dirtyArea.Union(rect));

	if(parent && !dirtyArea.IsEmpty())
	{
		parent->setDirty();
	}
}

// Called when a region of the WebWidget, given by clip_rect, should be
// scrolled by the specified dx and dy amounts.
void WebViewProxy::didScrollRect(int dx, int dy, const WebKit::WebRect& clip_rect)
{
	if(parent && dirtyArea.IsEmpty() && !isPopupsDirty)
		parent->setDirty();

	dirtyArea = gfx::Rect(width, height);

	for(std::vector<PopupWidget*>::iterator i = popups.begin(); i != popups.end(); i++)
		(*i)->didScrollWebView(dx, dy);

	isPopupsDirty = true;
}

// This method is called to instruct the window containing the WebWidget to
// close.  Note: This method should just be the trigger that causes the
// WebWidget to eventually close.  It should not actually be destroyed until
// after this call returns.
void WebViewProxy::closeWidgetSoon()
{
}

// This method is called to focus the window containing the WebWidget so
// that it receives keyboard events.
void WebViewProxy::didFocus()
{
	view->setFocus(true);
	checkKeyboardFocus();
}

// This method is called to unfocus the window containing the WebWidget so that
// it no longer receives keyboard events.
void WebViewProxy::didBlur()
{
	view->setFocus(false);
	checkKeyboardFocus();
}
/*
PopupWidget* WebViewProxy::GetPopupWidget() {
	if (this == WebCore::delegate())
    return shell_->webViewHost();
  if (this == shell_->popup_delegate())
    return shell_->popupHost();
  return NULL;
}
*/
void WebViewProxy::didChangeCursor(const WebKit::WebCursorInfo& cursor)
{
	// mgdesign:
	// remove
	//WebKit::WebCursorInfo curCursorType;
	//curCursor.GetCursorInfo(&curCursorType);
	//if(cursor.type!=curCursorType.type)
	{
    curCursor.InitFromCursorInfo(cursor);
#if defined(WIN32)
		Awesomium::WebCore::Get().queueEvent(new WebViewEvents::ChangeCursor(parent, curCursor.GetCursor(GetModuleHandle(0))));
#endif
	}
}

// Returns the rectangle of the WebWidget in screen coordinates.
WebKit::WebRect WebViewProxy::windowRect()
{
	return WebKit::WebRect(0, 0, width, height);
}

// This method is called to re-position the WebWidget on the screen.  The given
// rect is in screen coordinates.  The implementation may choose to ignore
// this call or modify the given rect.  This method may be called before Show
// has been called.
// TODO(darin): this is more of a request; does this need to take effect
// synchronously?
void WebViewProxy::setWindowRect(const WebKit::WebRect& rect)
{
	int t=0;
}

// Returns the rectangle of the window in which this WebWidget is embeded in.
WebKit::WebRect WebViewProxy::rootWindowRect()
{
	return WebKit::WebRect(0, 0, width, height);
}

WebKit::WebRect WebViewProxy::windowResizerRect()
{
	return WebKit::WebRect();
}

void WebViewProxy::runModal()
{
	int t=0;
}

void WebViewProxy::show(WebKit::WebNavigationPolicy policy) 
{
	int _t=0;
	/*
 if (PopupWidget* host = GetPopupWidget()) {
    HWND root = GetAncestor(host->view_handle(), GA_ROOT);
    ShowWindow(root, SW_SHOW);
    UpdateWindow(root);
  }*/
	
}

WebKit::WebScreenInfo WebViewProxy::screenInfo() {
	WebKit::WebScreenInfo ret;
	ret.availableRect = WebKit::WebRect(0,0,width,height); // PRHFIXME: Huge hack, hardcode some screen 
	ret.depth = 24;
	ret.isMonochrome = false;
	ret.depthPerComponent = 8;
	ret.rect = WebKit::WebRect(0,0,width,height);
	return ret;
}

//  --------------------------------------------------------------------------------------------------





void WebViewProxy::handleMouseEvent(WebKit::WebInputEvent::Type type, short buttonID)
{
	int x = mouseX;
	int y = mouseY;

	WebKit::WebMouseEvent event;
	initializeWebEvent(event,type);
	event.x = x;
	event.y = y;
	event.globalX = x;
	event.globalY = y;
	event.button = WebKit::WebMouseEvent::ButtonNone;
	event.modifiers |= buttonState;

	if(type == WebKit::WebInputEvent::MouseDown || type == WebKit::WebInputEvent::MouseUp)
	{
		int buttonChangeMask = 0;

		switch(buttonID)
		{
		case Awesomium::LEFT_MOUSE_BTN:
			buttonChangeMask = WebKit::WebInputEvent::LeftButtonDown;
			event.button = WebKit::WebMouseEvent::ButtonLeft;
			break;
		case Awesomium::MIDDLE_MOUSE_BTN:
			buttonChangeMask = WebKit::WebInputEvent::MiddleButtonDown;
			event.button = WebKit::WebMouseEvent::ButtonMiddle;
			break;
		case Awesomium::RIGHT_MOUSE_BTN:
			buttonChangeMask = WebKit::WebInputEvent::RightButtonDown;
			event.button = WebKit::WebMouseEvent::ButtonRight;
			break;
		}
		if (type == WebKit::WebInputEvent::MouseDown) {
			buttonState |= buttonChangeMask;
		} else {
			buttonState &= (~buttonChangeMask);
		}
	}
	if (buttonState) {
		event.clickCount = 1;
	}

	for(std::vector<PopupWidget*>::reverse_iterator i = popups.rbegin(); i != popups.rend(); i++)
	{
		if((*i)->isVisible())
		{
			int localX = mouseX;
			int localY = mouseY;
			(*i)->translatePointRelative(localX, localY);

			event.x = localX;
			event.y = localY;

			if((*i)->getWidget()->handleInputEvent(event))
				return;
		}
	}

	view->handleInputEvent(event);

	if(type != WebKit::WebInputEvent::MouseMove)
		checkKeyboardFocus();
}

void WebViewProxy::closeAllPopups()
{
	for(std::vector<PopupWidget*>::iterator i = popups.begin(); i != popups.end();)
	{
		delete (*i);
		i = popups.erase(i);	
	}

	invalidatePopups();
}

void WebViewProxy::closePopup(PopupWidget* popup)
{
	for(std::vector<PopupWidget*>::iterator i = popups.begin(); i != popups.end(); i++)
	{
		if((*i) == popup)
		{
			WebKit::WebRect winRect = (*i)->windowRect();
			didInvalidateRect(winRect);

			delete (*i);
			popups.erase(i);
			invalidatePopups();

			break;
		}
	}
}

void WebViewProxy::checkKeyboardFocus()
{
	executeJavascript("Client.____checkKeyboardFocus(document.activeElement != document.body)");
}

void WebViewProxy::overrideIFrameWindow(const std::wstring& frameName)
{
	
//	WebFrame* frame = view->GetFrameWithName(frameName);
	WebFrame* frame = view->findFrameByName(frameName);


	if(frame)
	{
		WebKit::WebURLRequest request(GURL("javascript:window.self = window.top;void(0);"));
		frame->loadRequest(request);
	}
}

bool WebViewProxy::navigate(NavigationEntry& entry, bool reload)
{
  // inspired/derived from TestShell::Navigate

  // Get the right target frame for the entry.
  WebFrame* frame = view->mainFrame();
  if (!entry.GetTargetFrame().empty()) {
      frame = view->findFrameByName(
          WideToUTF16Hack(entry.GetTargetFrame()));
  }
  // TODO(mpcomplete): should we clear the target frame, or should
  // back/forward navigations maintain the target frame?

  // A navigation resulting from loading a javascript URL should not be
  // treated as a browser initiated event.  Instead, we want it to look as if
  // the page initiated any load resulting from JS execution.
  if (!entry.GetURL().SchemeIs("javascript")) {
    view->mainFrame()->dataSource()->setExtraData(new NavigationExtraRequestData(entry.GetPageID()));
    // test_shell // delegate_-> set_pending_extra_data(new TestShellExtraData(entry.GetPageID()));
  }

  // If we are reloading, then WebKit will use the state of the current page.
  // Otherwise, we give it the state to navigate to.
  if (reload) {
    frame->reload();
  } else if (!entry.GetContentState().empty()) {
    DCHECK_NE(entry.GetPageID(), -1);
    frame->loadHistoryItem(
        webkit_glue::HistoryItemFromString(entry.GetContentState()));
  } else {
    // test_shell // DCHECK_EQ(entry.GetPageID(), -1);
    frame->loadRequest(WebURLRequest(entry.GetURL()));
  }

  // test_shell // // In case LoadRequest failed before DidCreateDataSource was called.
  // test_shell // delegate_->set_pending_extra_data(NULL);

  // Restore focus to the main frame prior to loading new request.
  // This makes sure that we don't have a focused iframe. Otherwise, that
  // iframe would keep focus when the SetFocus called immediately after
  // LoadRequest, thus making some tests fail (see http://b/issue?id=845337
  // for more details).
  view->setFocusedFrame(frame);
  
  // test_shell // SetFocus(webViewHost(), true);

	return true;
}

void WebViewProxy::updateForCommittedLoad(WebFrame* frame, bool is_new_navigation)
{
	//PRHFIXME: old code used view->GetMainFrame() instead of frame. Why?
	NavigationExtraRequestData* extra_data = static_cast<NavigationExtraRequestData*>(frame->dataSource()->extraData());

	if(is_new_navigation) 
	{
		// New navigation.
		updateSessionHistory(frame);
		pageID = nextPageID++;
	}
	else if (extra_data && extra_data->pending_page_id != -1 && !extra_data->request_committed)
	{
		// This is a successful session history navigation!
		updateSessionHistory(frame);
		pageID = extra_data->pending_page_id;
	}

	// Don't update session history multiple times.
	if(extra_data)
		extra_data->request_committed = true;

	updateURL(frame);
}

void WebViewProxy::updateURL(WebFrame* frame)
{
	WebDataSource* ds = frame->dataSource();
	DCHECK(ds);

	const WebKit::WebURLRequest& request = ds->request();

	// Type is unused.
	scoped_ptr<NavigationEntry> entry(new NavigationEntry);

	// Bug 654101: the referrer will be empty on https->http transitions. It
	// would be nice if we could get the real referrer from somewhere.
	entry->SetPageID(pageID);
	if (ds->hasUnreachableURL()) {
		entry->SetURL(GURL(ds->unreachableURL()));
	} else {
		entry->SetURL(GURL(request.url()));
	}

  const WebHistoryItem& history_item = frame->currentHistoryItem();
  if (!history_item.isNull())
    entry->SetContentState(webkit_glue::HistoryItemToString(history_item));

  navController->DidNavigateToEntry(entry.release());
  //shell_->UpdateNavigationControls();

  last_page_id_updated_ = std::max(last_page_id_updated_, page_id_);

}

void WebViewProxy::updateSessionHistory(WebFrame* frame)
{
	// If we have a valid page ID at this point, then it corresponds to the page
	// we are navigating away from.  Otherwise, this is the first navigation, so
	// there is no past session history to record.
	if (pageID == -1)
	return;

	NavigationEntry* entry = static_cast<NavigationEntry*>(
	navController->GetEntryWithPageID(pageID));

	if(!entry)
		return;

  const WebHistoryItem& history_item =  view->mainFrame()->previousHistoryItem();
  if (history_item.isNull())
    return;

	entry->SetContentState(webkit_glue::HistoryItemToString(history_item));

}
